package com.soboot.base.util;

import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.soboot.log.utils.LogUtil;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * @Author:
 * @createTime: 2023年01月28日 20:14:33
 * @version:
 * @Description: 重试工具类
 * @Copyright:
 */
public class RetryUtil {

    /**
     *
     * @param sleepTime 等待时间
     * @param timeUnit
     * @param attemptNumber 重试次数
     * @param supply
     * @return
     * @throws Exception
     */
    public static Object retry(long sleepTime, TimeUnit timeUnit, int attemptNumber,Supplier<Callable> supply) throws Exception {

        //定义重试机制
        Retryer<Object> retryer = RetryerBuilder.<Object>newBuilder()
                .retryIfException()
                .retryIfRuntimeException()
                .retryIfExceptionOfType(Exception.class)
                .retryIfException(Predicates.equalTo(new Exception()))
                .retryIfResult(Predicates.equalTo(false))

                //等待策略：每次请求间隔1s
                //fixedWait 固定X秒后重试
                //noWait不等时间直接重试
                //incrementingWait 第一个参数为第一次重试时间，后面会通过设置间隔递增秒数重试
                //randomWait 随机等待设置范围内的时间重试
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, timeUnit))

                //停止策略 : 尝试请求6次
                .withStopStrategy(StopStrategies.stopAfterAttempt(attemptNumber))

                //日志埋点
                .withRetryListener(new CurrentRetryListener())
                .build();

        //利用重试器调用请求
        return retryer.call(supply.get());
    }

    private static class CurrentRetryListener implements RetryListener {
        @Override
        public <V> void onRetry(Attempt<V> attempt) {

            LogUtil.info("回调监听器，当前是第{}次执行",attempt.getAttemptNumber());
        }
    }
}
